#include "ParticleSystem.h"
#include "ParticleManager.h"
#include "SB.h"
#include "hRandom.h"

void ParticleSystem::resetParticles()
{
    m_bRender = true;
    m_bStopSpawning = false;
    
    // get an aproximate number of the simultaneous particles that will have the system
	float spawnRatio = info.particlesLife / (float)info.nParticles;
	switch(info.type)
	{
        case Burst:
            for(int i=0; i<info.nParticles; i++)
            {
                particles[i].nframe = 0;
                particles[i].dummy1 = 0;
                particles[i].dummy2 = 0;
                particles[i].isDead = true;
                initializeParticle(particles[i]);
            }
            break;
        case Fountain:
            for(int i=0; i<info.nParticles; i++)
            {
                initializeParticle(particles[i]);
                particles[i].nframe = 0;
                particles[i].dummy1 = 0;
                particles[i].dummy2 = 0;
                //we want particles prepared to be spawned with the spawnRatio ratio, so we set'em all alive but invisible
                particles[i].life = spawnRatio * i;
                particles[i].isDead = false;
                particles[i].color[3] = 0;
            }
            break;
        default:
            break;
	}
}

void ParticleSystem::initialize(const char* particleSystemName, const Vector3 &pPosition, const Vector3 &pDirection)
{
	particles.clear();
 	info = ParticleManager::instance().getBaseParticleSystems()[particleSystemName];
	position = pPosition;
	customDirection = pDirection;
    
	// if has a direction specified by code, initialize it now
	if (customDirection != Vector3(0,0,0))
	{
		info.directionVarianceMin = info.directionVarianceMin + customDirection * 0.5f;
		info.directionVarianceMax = info.directionVarianceMax + customDirection ;
	}
    
	particles.resize(info.nParticles);
    
    resetParticles();
}

void ParticleSystem::initializeParticle( Particle &particle )
{
    Vector4 vColor = hRandom::getRandomVector4(info.colorVarianceMin, info.colorVarianceMax);
    
	particle.color[0] = info.color.x + vColor.x;
	particle.color[1] = info.color.y + vColor.y;
	particle.color[2] = info.color.z + vColor.z;
	particle.color[3] = info.color.w + vColor.w;
	particle.size = info.sizeIni;
	Vector3 v = hRandom::getRandomVector3(info.positionVarianceMin, info.positionVarianceMax);
	particle.position = position + info.position + v;
	v = hRandom::getRandomVector3(info.directionVarianceMin, info.directionVarianceMax);
	particle.direction = info.direction + v;
	v = hRandom::getRandomVector3(info.accelerationVarianceMin, info.accelerationVarianceMax);
	particle.acceleration = info.acceleration + v;
	particle.rotation = info.particlesRotation + hRandom::getRandom(-info.particlesRotationVariance, info.particlesRotationVariance);
	particle.rotationSpeed = info.particlesRotationSpeed + hRandom::getRandom(-info.particlesRotationSpeedVariance, info.particlesRotationSpeedVariance);
	particle.life = info.particlesLife;
}

void ParticleSystem::die()
{
    info.type = Burst;
    info.systemLife = -1.0f;
    for(size_t i=0; i<particles.size(); i++)
	{
        particles[i].life = -1.0f;
    }
}

void ParticleSystem::update()
{
	info.systemLife -= SB::dt;
    
	// update each particle
	float aux;
    // start always with isDead true except if stop spawning is selected
	isDead = !m_bStopSpawning;
    m_bRender = false;
    
	for(size_t i=0; i<particles.size(); i++)
	{
		if (particles[i].life < 0)
		{
			if (info.type == Fountain && info.systemLife > 0 && !m_bStopSpawning)
			{
				initializeParticle(particles[i]);
			}
			else
			{
                // if system life is bigger than zero, the particle system hasnt died yet
                if (info.systemLife > 0)
                    isDead = false;
				continue;
			}
		}
        m_bRender = true;
		isDead = false;
		particles[i].direction += particles[i].acceleration * SB::dt;
		particles[i].position += particles[i].direction * SB::dt;
		particles[i].rotation += particles[i].rotationSpeed * SB::dt;
		particles[i].life -= SB::dt;
		// get the alpha
		aux = info.particlesLife - particles[i].life;
		if (aux < info.fadeIn)
		{
			particles[i].color[3] = aux/info.fadeIn;
		}
		else
		{
			aux = info.particlesLife - info.fadeIn;
			particles[i].color[3] = particles[i].life/aux;
		}
		particles[i].color[3] *= info.color[3];
        
		if (particles[i].life > info.particlesLife - info.fadeIn)
		{
			particles[i].size = info.sizeIni + ((aux/info.fadeIn) * (info.size - info.sizeIni));
		}
		else if (particles[i].life < info.fadeOut)
		{
			particles[i].size = info.sizeEnd + ((particles[i].life/info.fadeOut) * ( info.size - info.sizeEnd ));
		}
		else
		{
			particles[i].size = info.size;
		}
	}
}